package com.hmall.common.config;

import cn.hutool.core.util.ObjectUtil;
import com.hmall.common.utils.UserContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConversionException;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.lang.Nullable;

import java.lang.reflect.Type;

@Configuration
@ConditionalOnClass(RabbitTemplate.class)
@Slf4j
public class MqConfig {

    //方法一配置MessageConverter使得在信息发送前装配用户信息，并且在消息接收后，从消息的属性中获取用户信息，并将其设置到当前线程上下文中。
    //
    @Bean
    public MessageConverter messageConverter() {
        Jackson2JsonMessageConverter converter = new Jackson2JsonMessageConverter() {

            //这里为什么可以重写这两个方法呢？因为Jackson2JsonMessageConverter继承了AbstractMessageConverter
            //fromMessage方法作用是将消息头的用户信息解析出来，然后设置到UserContext中
            @Override
            public Object fromMessage(Message message) throws MessageConversionException { // 明确指定AMQP的Message类型
                Long userId = (Long) message.getMessageProperties().getHeader("userInfo"); // 强制类型转换
                log.info("解析Amqp消息的用户信息: userId:" + userId);
                if (ObjectUtil.isNotNull(userId)) {
                    UserContext.setUser(userId);
                }
                //将Mq传递的Message转换为消费者需要的对象
                return super.fromMessage(message);
            }

            //createMessage方法的参数objectToConvert是需要发送的对象，messageProperties是消息属性，genericType是消息类型
            @Override
            public Message  createMessage(Object objectToConvert,
                                          MessageProperties messageProperties,
                                          @Nullable Type genericType) throws MessageConversionException {
                Long userId = UserContext.getUser();
                log.info("将当前用户信息放入消息头中：" + userId);
                if(ObjectUtil.isNotNull(userId)){
                    messageProperties.setHeader("userInfo", userId);
                }
                //将需要发送的对象转换为可以通过RabbitMQ传递的Message本质是一个字节数组
                return super.createMessage(objectToConvert, messageProperties, genericType);

            }
        };
        //配置自动创建消息id，用于识别不同消息，也可以在业务中基于ID判断是否是重复消息避免消费者重复消费
        converter.setCreateMessageIds(true);
        //- 唯一消息ID
        //- 业务状态判断 更推荐
        return converter;
    }

    @Bean
    public RabbitMqHelper rabbitMqHelper(RabbitTemplate rabbitTemplate){
        return new RabbitMqHelper(rabbitTemplate);
    }

//    @Bean
//    public ErrorMessageConfig errorMessageConfig() {
//        return new ErrorMessageConfig();
//    }


    //方法二配置RabbitTemplate
//    @Bean
//    public RabbitTemplate rabbitTemplate (ConnectionFactory connectionFactory) {
//        RabbitTemplate rabbitTemplate = new RabbitTemplate (connectionFactory);
//        //消息发送前处理：在消息发送前，从当前线程上下文中获取用户信息，并将其设置到消息的属性中。
//        rabbitTemplate.addBeforePublishPostProcessors (message -> {
//            MessageProperties properties = message.getMessageProperties();
//            if (properties != null) {
//                // 获取当前线程上下文中的用户信息
//                Long userId = UserContext.getUser();
//                if (userId != null) {
//                    // 设置 userInfo 请求头
//                    log.info("请求装配Amqp消息的用户信息:userId: {}", userId);
//                    properties.setHeader("userInfo", userId);
//                }
//            }
//            return message;
//        });
        //消息接收后处理：在消息接收后，从消息的属性中获取用户信息，并将其设置到当前线程上下文中。
//        rabbitTemplate.addAfterReceivePostProcessors (message -> {
//            if (message != null) {
//                MessageProperties properties = message.getMessageProperties();
//                if (properties != null) {
//                    // 清除 userInfo 请求头
//                    Long userId = properties.getHeader("userInfo");
//                    if (userId != null) {
//                        UserContext.setUser (userId);
//                    }
//                }
//            }
//            return message;
//        });
        //设置消息转换器：使用自定义的 messageConverter 进行消息转换。
//        rabbitTemplate.setMessageConverter (messageConverter());
//        return rabbitTemplate;
//    }
}